package com.mall.common.dao.impl;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Fetch;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import com.mall.common.bean.Order;
import com.mall.common.bean.Order.Direction;
import com.mall.common.bean.Pager;
import com.mall.common.bean.SearchFilter;
import com.mall.common.bean.SearchFilter.Operator;
import com.mall.common.dao.BaseDao;
import com.mall.common.domain.PriorityEntity;
import com.mall.common.hibernate.Finder;
import com.mall.common.util.AppContext;
import com.mall.common.util.DateHelper;
import com.mall.common.web.Servlets;

/**
 * Dao实现类 - Dao实现类基类
 */
@Repository
public class BaseDaoImpl<T, PK extends Number> implements BaseDao<T, PK> {

	private Class<T> entityClass;
	private static volatile long increased = 0L;
	@PersistenceContext
	protected EntityManager entityManager;
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public BaseDaoImpl() {
		this.entityClass = null;
        Class c = getClass();
        Type type = c.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] parameterizedType = ((ParameterizedType) type).getActualTypeArguments();
            this.entityClass = (Class<T>) parameterizedType[0];
        }
	}

	public Class<T> getEntityClass() {
		return entityClass;
	}

	public EntityManager getEntityManager(){
		return entityManager;
	}
	
	public T find(Number id) {
		if (id != null){
			return entityManager.find(entityClass, id);
		} else {
			return null;
		}
	}
	
	public List<T> findList(Integer first, Integer count, List<SearchFilter> filters, List<Order> orders) {
		CriteriaBuilder criteriabuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<T> criteriaquery = criteriabuilder.createQuery(entityClass);
		criteriaquery.select(criteriaquery.from(entityClass));
		return findList(criteriaquery, first, count, filters, orders);
	}

	public List<T> findList(CriteriaQuery<T> criteriaQuery, Integer first, Integer count, 
			List<SearchFilter> filterList, List<Order> orderList) {
		Assert.notNull(criteriaQuery);
		Assert.notNull(criteriaQuery.getSelection());
		Assert.notEmpty(criteriaQuery.getRoots());
		appendWhere(criteriaQuery, filterList);
		appendOrders(criteriaQuery, orderList);
		TypedQuery<T> typedquery = entityManager.createQuery(criteriaQuery).setFlushMode(FlushModeType.COMMIT);
		if (first != null) {
			typedquery.setFirstResult(first.intValue());
		}
		if (count != null) {
			typedquery.setMaxResults(count.intValue());
		}
		return typedquery.getResultList();
	}
	
	public long count(SearchFilter[] filters) {
		CriteriaBuilder criteriabuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<T> criteriaquery = criteriabuilder.createQuery(entityClass);
		criteriaquery.select(criteriaquery.from(entityClass));
		return count(criteriaquery, filters == null ? null : Arrays.asList(filters)).longValue();
	}

	public Pager findPage(Pager pager) {
		Order orderBy = Servlets.getOrderBy(AppContext.getRequest());
		if(orderBy != null){
			pager.addOrder(orderBy);
		}
		CriteriaBuilder criteriabuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<T> criteriaquery = criteriabuilder.createQuery(entityClass);
		criteriaquery.select(criteriaquery.from(entityClass));
		return findByPager(criteriaquery, pager);
	}

	@SuppressWarnings("rawtypes")
	public Pager findByPager(CriteriaQuery<T> criteriaQuery, Pager pager) {
		Assert.notNull(criteriaQuery);
		Assert.notNull(criteriaQuery.getSelection());
		Assert.notEmpty(criteriaQuery.getRoots());
		if (pager == null){
			pager = new Pager();
		}
		appendWhere(criteriaQuery, pager.getFilterList());
		appendOrders(criteriaQuery, pager.getOrderList());
		
		long totalCount = count(criteriaQuery, null).longValue();
		int i = (int)Math.ceil((double)totalCount / (double)pager.getPageSize());
		if (i < pager.getPageNumber()){
			pager.setPageNumber(i);
		}
		TypedQuery typedquery = entityManager.createQuery(criteriaQuery).setFlushMode(FlushModeType.COMMIT);
		typedquery.setFirstResult((pager.getPageNumber() - 1) * pager.getPageSize());
		typedquery.setMaxResults(pager.getPageSize());
		pager.setTotalCount(new Long(totalCount).intValue());
		pager.setList(typedquery.getResultList());
		return pager;
	}

	@SuppressWarnings("unchecked")
	private Root<T> getRoot(CriteriaQuery<T> criteriaquery) {
		if (criteriaquery != null){
			return getRoot(criteriaquery, criteriaquery.getResultType());
		} else {
			return null;
		}
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Root getRoot(CriteriaQuery criteriaquery, Class clazz) {
		if (criteriaquery != null && criteriaquery.getRoots() != null && clazz != null){
			for (Iterator iterator = criteriaquery.getRoots().iterator(); iterator.hasNext();) {
				Root root = (Root)iterator.next();
				if (clazz.equals(root.getJavaType())){
					return (Root)root.as(clazz);
				}
			}
		}
		return null;
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void joinTable(From from, From from1) {
		for (Iterator<Join> iterator = from.getJoins().iterator(); iterator.hasNext();) {
			Join join = (Join)iterator.next();
			Join join1 = from1.join(join.getAttribute().getName(), join.getJoinType());
			join1.alias(getAlias(((Selection) (join))));
			joinTable(((From) (join)), ((From) (join1)));
		}

		for (Iterator iterator1 = from.getFetches().iterator(); iterator1.hasNext();){
			Fetch fetch = (Fetch)iterator1.next();
			Fetch fetch1 = from1.fetch(fetch.getAttribute().getName());
			fetchTable(fetch, fetch1);
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void fetchTable(Fetch fetch, Fetch fetch1) {
		for (Iterator<Fetch> iterator = fetch.getFetches().iterator(); iterator.hasNext(); ) {
			Fetch fetch2 = (Fetch)iterator.next();
			Fetch fetch3 = fetch1.fetch(fetch2.getAttribute().getName());
			fetchTable(fetch2, fetch3);
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<T> get(Number[] ids) {
		if(ids == null || ids.length == 0){
			return new ArrayList<T>();
		}
		String hql = "from " + entityClass.getName() + " as model where model.id in(:ids)";
		List<Number> params = Arrays.asList(ids);
		return entityManager.createQuery(hql).setParameter("ids", params).getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public List<T> get(String[] ids) {
		Assert.notEmpty(ids, "ids must not be empty");
		String hql = "from " + entityClass.getName() + " as model where model.id in(:ids)";
		List<Long> params = new ArrayList<Long>(ids.length);
		for(String id : ids){
			if(!StringUtils.isEmpty(id)){
				params.add(Long.parseLong(id));
			}
		}
		return entityManager.createQuery(hql).setParameter("ids", params).getResultList();
	}

	@SuppressWarnings("unchecked")
	public T get(String propertyName, Object value) {
		Assert.hasText(propertyName, "propertyName must not be empty");
		Assert.notNull(value, "value is required");
		String hql = "from " + entityClass.getName() + " as model where model." + propertyName + " = :propertyName";
		Query query =  entityManager.createQuery(hql).setParameter("propertyName", value);
		List<T> results = query.getResultList();
		if(results.isEmpty()){
			return null;
		}
		return results.get(0);
	}
	
	@SuppressWarnings("unchecked")
	public List<T> getList(String propertyName, Object value) {
		Assert.hasText(propertyName, "propertyName must not be empty");
		Assert.notNull(value, "value is required");
		String hql = "from " + entityClass.getName() + " as model where model." + propertyName + " = :propertyName";
		return entityManager.createQuery(hql).setParameter("propertyName", value).getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public List<T> getListLike(String propertyName, String value, Integer module) {
		Assert.hasText(propertyName, "propertyName must not be empty");
		Assert.notNull(value, "value is required");
		String hql = "from " + entityClass.getName() + " as model where model." + propertyName + " like :propertyName";
		Query query = entityManager.createQuery(hql);
		switch(module){
			case 1:
				query.setParameter("propertyName", "%" + value + "%");
				break;
			case 2:
				query.setParameter("propertyName", "%" + value);
				break;
			case 3:
				query.setParameter("propertyName", value + "%");
				break;
			default:
				query.setParameter("propertyName", "%" + value + "%");
		}
		return query.getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public List<T> getList(Long[] ids) {
		Assert.notNull(ids, "ids is required");
		String hql = "from " + entityClass.getName() + " as model where model.id in (:ids)";
		return getEntityManager().createQuery(hql).setParameter("ids", Arrays.asList(ids)).getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<T> getAll() {
		String hql = "from " + entityClass.getName() + " as model";
		return entityManager.createQuery(hql).getResultList();
	}
	
	public Long getTotalCount() {
		String hql = "select count(*) from " + entityClass.getName() + " as model";
		return (Long) entityManager.createQuery(hql).getSingleResult();
	}

	public boolean isUnique(String propertyName, Object oldValue, Object newValue) {
		Assert.hasText(propertyName, "propertyName must not be empty");
		Assert.notNull(newValue, "newValue is required");
		if (newValue == oldValue || newValue.equals(oldValue)) {
			return true;
		}
		if (newValue instanceof String) {
			if (oldValue != null && StringUtils.equalsIgnoreCase((String) oldValue, (String) newValue)) {
				return true;
			}
		}
		T object = get(propertyName, newValue);
		return (object == null);
	}
	
	public boolean isExist(String propertyName, Object value) {
		Assert.hasText(propertyName, "propertyName must not be empty");
		Assert.notNull(value, "value is required");
		T object = get(propertyName, value);
		return (object != null);
	}

	public void update(T entity) {
		Assert.notNull(entity, "entity is required");
		entityManager.merge(entity);
	}
	
	//获取表的别名
	@SuppressWarnings("rawtypes")
	private synchronized String getAlias(Selection selection) {
		if (selection != null) {
			String alias = selection.getAlias();
			if (alias == null) {
				if (increased >= 1000L){
					increased = 0L;
				}
				alias = "GeneratedAlias" + increased++;
				selection.alias(alias);
			}
			return alias;
		} else {
			return null;
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	protected Long count(CriteriaQuery<T> criteriaquery, List<SearchFilter> searchFilterList) {
		Assert.notNull(criteriaquery);
		Assert.notNull(criteriaquery.getSelection());
		Assert.notEmpty(criteriaquery.getRoots());
		
		appendWhere(criteriaquery, searchFilterList);
		
		CriteriaBuilder criteriabuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<Long> criteriaquery1 = criteriabuilder.createQuery(Long.class);
		
		for (Iterator iterator = criteriaquery.getRoots().iterator(); iterator.hasNext(); ) {
			Root<T> root = (Root<T>)iterator.next();
			Root root2 = criteriaquery1.from(root.getJavaType());
			root2.alias(getAlias((Selection)root));
			joinTable((From)root, (From)root2);
		}
		
		Root<T> root1 = getRoot(criteriaquery1, criteriaquery.getResultType());
		if (criteriaquery.isDistinct()) {
			criteriaquery1.select(criteriabuilder.countDistinct(root1));
		} else {
			criteriaquery1.select(criteriabuilder.count(root1));
		}
		if (criteriaquery.getGroupList() != null){
			criteriaquery1.groupBy(criteriaquery.getGroupList());
		}
		if (criteriaquery.getGroupRestriction() != null){
			criteriaquery1.having(criteriaquery.getGroupRestriction());
		}
		if (criteriaquery.getRestriction() != null){
			criteriaquery1.where(criteriaquery.getRestriction());
		}
		return (Long)entityManager.createQuery(criteriaquery1).setFlushMode(FlushModeType.COMMIT).getSingleResult();
	}
	
	/**
	 * 动态条件查询
	 * @param criteriaquery
	 * @param list
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void appendWhere(CriteriaQuery criteriaquery, List<SearchFilter> list) {
		if (criteriaquery == null || list == null || list.isEmpty()){
			return;
		}
		Root root = getRoot(criteriaquery);
		if (root == null){
			return;
		}
		CriteriaBuilder criteriabuilder = entityManager.getCriteriaBuilder();
		Predicate predicate = criteriaquery.getRestriction() == null ? criteriabuilder.conjunction() : criteriaquery.getRestriction();
		for (Iterator<SearchFilter> iterator = list.iterator(); iterator.hasNext();) {
			SearchFilter filter = iterator.next();
			if (filter != null && !StringUtils.isEmpty(filter.getFieldName())){
				Object value = filter.getValue();
				if(value != null){
					String str1 = filter.getFieldName();
					String[] params = str1.split("\\.");
					Path path = root.get(params[0]);
					for(int i = 1;i < params.length;i++){
						path = path.get(params[i]);
					}
					if(path.getJavaType() == Date.class){
						Date date = null;
						boolean dateDeal = false;
						if(value instanceof Date){
							date = (Date) value;
						}else{
							if(value.toString().trim().indexOf(" ") >= 0){
								date = DateHelper.string2Date(value.toString().trim(), "yyyy-MM-dd HH:mm:ss");
							}else{
								dateDeal = true;
								date =  DateHelper.string2Date(value.toString().trim(), "yyyy-MM-dd");
							}
						}
						if (filter.getOperator() == Operator.EQ) {
							predicate = criteriabuilder.and(predicate, criteriabuilder.equal(path, date));
						} else if (filter.getOperator() == Operator.NE) {
							predicate = criteriabuilder.and(predicate, criteriabuilder.notEqual(path, date));
						} else {
							switch (filter.operator) {
								case GT:
									predicate = criteriabuilder.and(predicate, criteriabuilder.greaterThan(path, date));
									break;
								case LT:
									if(dateDeal){
										date = DateUtils.addDays(date, 1);
									}
									predicate = criteriabuilder.and(predicate, criteriabuilder.lessThan(path, date));
									break;
								case GE:
									predicate = criteriabuilder.and(predicate, criteriabuilder.greaterThanOrEqualTo(path, date));
									break;
								case LE:
									if(dateDeal){
										date = DateUtils.addHours(date, 23);
										date = DateUtils.addMinutes(date, 59);
										date = DateUtils.addSeconds(date, 59);
									}
									predicate = criteriabuilder.and(predicate, criteriabuilder.lessThanOrEqualTo(path, date));
									break;
								case in:
									predicate = criteriabuilder.and(predicate, path.in(new Object[] {date}));
								case isNull:
									predicate = criteriabuilder.and(predicate, path.isNull());
								case isNotNull:
									predicate = criteriabuilder.and(predicate, path.isNotNull());
								default:;
							}
						}
					}else if(path.getJavaType() == Boolean.class ){
						
						Boolean bool = Boolean.valueOf(value.toString().trim());
						if (filter.getOperator() == Operator.EQ) {
							if(bool){
								predicate = criteriabuilder.and(predicate, criteriabuilder.isTrue(path));
							}else{
								predicate = criteriabuilder.and(predicate, criteriabuilder.isFalse(path));
							}
						} else if (filter.getOperator() == Operator.NE) {
							predicate = criteriabuilder.and(predicate, criteriabuilder.notEqual(path, bool));
						} else {
							switch (filter.operator) {
								case GT:
									predicate = criteriabuilder.and(predicate, criteriabuilder.greaterThan(path, bool));
									break;
								case LT:
									predicate = criteriabuilder.and(predicate, criteriabuilder.lessThan(path, bool));
									break;
								case GE:
									predicate = criteriabuilder.and(predicate, criteriabuilder.greaterThanOrEqualTo(path, bool));
									break;
								case LE:
									predicate = criteriabuilder.and(predicate, criteriabuilder.lessThanOrEqualTo(path, bool));
									break;
								case in:
									predicate = criteriabuilder.and(predicate, path.in(new Object[] {bool}));
									break;
								case isNull:
									predicate = criteriabuilder.and(predicate, path.isNull());
									break;
								case isNotNull:
									predicate = criteriabuilder.and(predicate, path.isNotNull());
									break;
								default:;
							}
						}
					}else if(path.getJavaType().isEnum()){
						if(filter.getOperator() == Operator.in){
							if(value instanceof Object[]){
								predicate = criteriabuilder.and(predicate, path.in((Object[])value));
							}else{
								predicate = criteriabuilder.and(predicate, path.in(new Object[] {value}));
							}
							continue;
						}
						Enum e = Enum.valueOf(path.getJavaType(), value.toString().trim());
						if (filter.getOperator() == Operator.EQ) {
							predicate = criteriabuilder.and(predicate, criteriabuilder.equal(path, e));
						} else if (filter.getOperator() == Operator.NE) {
							predicate = criteriabuilder.and(predicate, criteriabuilder.notEqual(path, e));
						} else {
							switch (filter.operator) {
								case GT:
									predicate = criteriabuilder.and(predicate, criteriabuilder.greaterThan(path, e));
									break;
								case LT:
									predicate = criteriabuilder.and(predicate, criteriabuilder.lessThan(path, e));
									break;
								case GE:
									predicate = criteriabuilder.and(predicate, criteriabuilder.greaterThanOrEqualTo(path, e));
									break;
								case LE:
									predicate = criteriabuilder.and(predicate, criteriabuilder.lessThanOrEqualTo(path, e));
									break;
								case isNull:
									predicate = criteriabuilder.and(predicate, path.isNull());
									break;
								case isNotNull:
									predicate = criteriabuilder.and(predicate, path.isNotNull());
									break;
								default:;
							}
						}
					}else if(path.getJavaType() == String.class){
						if(filter.getOperator() == Operator.in){
							if(value instanceof Object[]){
								predicate = criteriabuilder.and(predicate, path.in((Object[])value));
							}else{
								predicate = criteriabuilder.and(predicate, path.in(new Object[] {value}));
							}
							continue;
						}
						String str = value.toString().trim();
						if (filter.getOperator() == Operator.EQ) {
							if (filter.getIgnoreCase() != null && filter.getIgnoreCase()){
								predicate = criteriabuilder.and(predicate, criteriabuilder.equal(criteriabuilder.lower(path), str.toLowerCase()));
							} else {
								predicate = criteriabuilder.and(predicate, criteriabuilder.equal(path, str));
							}
						} else if (filter.getOperator() == Operator.NE) {
							if (filter.getIgnoreCase() != null && filter.getIgnoreCase()){
								predicate = criteriabuilder.and(predicate, criteriabuilder.notEqual(criteriabuilder.lower(path), str.toLowerCase()));
							} else {
								predicate = criteriabuilder.and(predicate, criteriabuilder.notEqual(path, str));
							}
						} else {
							switch (filter.operator) {
								case GT:
									predicate = criteriabuilder.and(predicate, criteriabuilder.greaterThan(path, str));
									break;
								case LT:
									predicate = criteriabuilder.and(predicate, criteriabuilder.lessThan(path, str));
									break;
								case GE:
									predicate = criteriabuilder.and(predicate, criteriabuilder.greaterThanOrEqualTo(path, str));
									break;
								case LE:
									predicate = criteriabuilder.and(predicate, criteriabuilder.lessThanOrEqualTo(path, str));
									break;
								case LIKE:
									predicate = criteriabuilder.and(predicate, criteriabuilder.like(path, "%" + str + "%"));
									break;
								case isNull:
									predicate = criteriabuilder.and(predicate, path.isNull());
									break;
								case isNotNull:
									predicate = criteriabuilder.and(predicate, path.isNotNull());
									break;
								default:;
							}
						}
					}else if(Number.class.isAssignableFrom(path.getJavaType())){
						if(filter.getOperator() == Operator.in){
							if(value instanceof Object[]){
								predicate = criteriabuilder.and(predicate, path.in((Object[])value));
							}else{
								predicate = criteriabuilder.and(predicate, path.in(new Object[] {value}));
							}
							continue;
						}
						if(path.getJavaType() == Long.class){
							value = Long.valueOf(value.toString());
						}else if(path.getJavaType() == BigDecimal.class){
							value = new BigDecimal(value.toString());
						}
						Number num = (Number) value;
						if (filter.getOperator() == Operator.EQ) {
							predicate = criteriabuilder.and(predicate, criteriabuilder.equal(path, num));
						} else if (filter.getOperator() == Operator.NE) {
							predicate = criteriabuilder.and(predicate, criteriabuilder.notEqual(path, num));
						} else {
							switch (filter.operator) {
								case GT:
									predicate = criteriabuilder.and(predicate, criteriabuilder.gt(path, num));
									break;
								case LT:
									predicate = criteriabuilder.and(predicate, criteriabuilder.lt(path, num));
									break;
								case GE:
									predicate = criteriabuilder.and(predicate, criteriabuilder.ge(path, num));
									break;
								case LE:
									predicate = criteriabuilder.and(predicate, criteriabuilder.le(path, num));
									break;
								case isNull:
									predicate = criteriabuilder.and(predicate, path.isNull());
									break;
								case isNotNull:
									predicate = criteriabuilder.and(predicate, path.isNotNull());
									break;
								default:;
							}
						}
					}else if(java.util.Set.class.isAssignableFrom(path.getJavaType())){
						switch (filter.operator) {
							case in:
								predicate = criteriabuilder.and(predicate, root.join(params[0]).get("id").in(value));
								break;
							case isNull:
								predicate = criteriabuilder.and(predicate, root.join(params[0],JoinType.LEFT).isNull());
								break;
							case isNotNull:
								predicate = criteriabuilder.and(predicate, root.join(params[0],JoinType.LEFT).isNotNull());
								break;
							default:;
						}
					}
				}else{
					String str1 = filter.getFieldName();
					String[] params = str1.split("\\.");
					Path path = root.get(params[0]);
					for(int i = 1;i < params.length;i++){
						path = path.get(params[i]);
					}
					switch (filter.operator) {
						case isNull:
							predicate = criteriabuilder.and(predicate, path.isNull());
							break;
						case isNotNull:
							predicate = criteriabuilder.and(predicate, path.isNotNull());
							break;
						default:;
					}
				}
			}
		}
		criteriaquery.where(predicate);
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void appendOrders(CriteriaQuery criteriaQuery, List<Order> orderList) {
		CriteriaBuilder criteriabuilder = entityManager.getCriteriaBuilder();
		Root root = getRoot(criteriaQuery);
		if (root == null){
			return;
		}
		
		List<javax.persistence.criteria.Order> arraylist = new ArrayList<javax.persistence.criteria.Order>();
		if (!criteriaQuery.getOrderList().isEmpty()){
			arraylist.addAll(criteriaQuery.getOrderList());
		}
		
		if(orderList != null && !orderList.isEmpty()) {
			for (Iterator<Order> iterator = orderList.iterator(); iterator.hasNext();) {
				Order order = iterator.next();
				String str1 = order.getFieldName();
				String[] params = str1.split("\\.");
				Path path = root.get(params[0]);
				for(int i = 1;i < params.length;i++){
					path = path.get(params[i]);
				}
				if (order.getDirection() == Direction.asc){
					arraylist.add(criteriabuilder.asc(path));
				} else if (order.getDirection() == Direction.desc) {
					arraylist.add(criteriabuilder.desc(path));
				}
			}
		}
		
		if(arraylist.size() == 0){
			if (PriorityEntity.class.isAssignableFrom(entityClass)){
				arraylist.add(criteriabuilder.asc(root.get(PriorityEntity.ORDER_PROPERTY_NAME)));
			} else {
				arraylist.add(criteriabuilder.desc(root.get("createDate")));
			}
		}
		criteriaQuery.orderBy(arraylist);
	}
	
	/**
	 * 通过Finder获得分页数据
	 * 
	 * @param finder
	 *            Finder对象
	 * @param pageNo
	 *            页码
	 * @param pageSize
	 *            每页条数
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public  Pager findByPager(Pager pager, Finder finder) {
		if (pager == null) {
			pager = new Pager();
		}
		int totalCount = countQueryResult(finder);
		if (totalCount < 1) {
			pager.setList(new ArrayList());
			return pager;
		}
		pager.setTotalCount(totalCount);
		if(pager.getPageCount() < pager.getPageNumber()){
			pager.setPageNumber(pager.getPageCount());
		}
		Query query = entityManager.createQuery(finder.getOrigHql());
		finder.setParamsToQuery(query);
		query.setFirstResult(pager.getFirstResult());
		query.setMaxResults(pager.getPageSize());
		List list = query.getResultList();
		pager.setList(list);
		return pager;
	}
	
	/**
	 * 获得Finder的记录总数
	 * 
	 * @param finder
	 * @return
	 */
	public int countQueryResult(Finder finder) {
		Query query = entityManager.createQuery(finder.getRowCountHql());
		finder.setParamsToQuery(query);
		return ((Number)query.getSingleResult()).intValue();
	}
	
	/**
	 * 获得Finder的记录总数
	 * 
	 * @param finder
	 * @return
	 */
	public int countSQLQueryResult(Finder finder) {
		Query query = entityManager.createNativeQuery(finder.getRowCountHql());
		finder.setParamsToQuery(query);
		return ((Number)query.getSingleResult()).intValue();
	}

	@Override
	public void persist(T entity) {
		Assert.notNull(entity);
		entityManager.persist(entity);
	}

	@Override
	public void remove(T entity) {
		if (entity != null){
			entityManager.remove(entity);
		}
	}
	
	@Override
	public void remove(Number id) {
		T entity = this.find(id);
		this.remove(entity);
	}

	@Override
	public void detach(T entity) {
		entityManager.detach(entity);
	}
	
	public Number getIdentifier(T entity) {
		Assert.notNull(entity);
		return (Number)entityManager.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(entity);
	}
	
	public boolean isManaged(T entity) {
		return entityManager.contains(entity);
	}
	
	public void clear() {
		entityManager.clear();
	}

	public void flush() {
		entityManager.flush();
	}

	@Override
	public void refresh(T entity) {
		Assert.notNull(entity);
		entityManager.refresh(entity);
	}
	
	public void lock(T entity, LockModeType lockModeType) {
		if (entity != null && lockModeType != null){
			entityManager.lock(entity, lockModeType);
		}
	}
	
	public T merge(T entity) {
		Assert.notNull(entity);
		return entityManager.merge(entity);
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Pager findByPagerForHessian(Pager pager, Finder finder) {
		if (pager == null) {
			pager = new Pager();
		}
		Query query = entityManager.createQuery(finder.getRowCountHqlForHessian());
		finder.setParamsToQuery(query);
		int totalCount = ((Number)query.getSingleResult()).intValue();
		if (totalCount < 1) {
			pager.setList(new ArrayList());
			return pager;
		}
		pager.setTotalCount(totalCount);
		if(pager.getPageCount() < pager.getPageNumber()){
			pager.setPageNumber(pager.getPageCount());
		}
		query = entityManager.createQuery(finder.getOrigHql());
		finder.setParamsToQuery(query);
		query.setFirstResult(pager.getFirstResult());
		query.setMaxResults(pager.getPageSize());
		List list = query.getResultList();
		pager.setList(list);
		return pager;
	}

}